package gminet.infra.db;

import gminet.infra.config.ConfigException;
import gminet.infra.toolkit.Cryptography;
import gminet.infra.toolkit.StringToolkit;

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;

public class PoolManager {

    private static PoolManager instance;

    private static Exception exception;

    private Driver driver;

    private ConnectionPool pool;


    private PoolManager() {
        loadDriver();
        createPools();
    }

    public static boolean initialized() throws DBException {

        return instance != null;
    }

    public static void initialize(String fileName) throws DBException {

        if (instance == null) {
            try {
                ConfigPropertiesDB.initialize(fileName);
                PoolManager.instance = new PoolManager();
                PoolManager.exception = null;
            } catch (ConfigException ce) {
                throw new DBException(ce.getMessage());
            }
        }
    }

    private void loadDriver() throws DBException {

        try {
            String driverClassName = ConfigPropertiesDB.getDriverDB();
            Driver driver = (Driver) Class.forName(driverClassName).newInstance();
            DriverManager.registerDriver(driver);
            this.driver = driver;
        } catch (Exception e) {
            PoolManager.exception = e;
            throw new DBException(e.getMessage());
        }
    }

    private void createPools() throws DBException {

        try {
            String url = ConfigPropertiesDB.getUrlDB();
            String user = ConfigPropertiesDB.getUserDB();
            String password = ConfigPropertiesDB.getPasswordDB();
            if (StringToolkit.isFill(password) && Cryptography.isAutoCrypt(password)) {
                password = Cryptography.autoDecrypt(password);
            }
            int maxConns = ConfigPropertiesDB.getMaxConnectionDB();
            int initConns = ConfigPropertiesDB.getInitConnectionDB();
            pool = new ConnectionPool(url, user, password, maxConns, initConns);
        } catch (Exception e) {
            PoolManager.exception = e;
            throw new DBException(e.getMessage());
        }
    }

    public static synchronized PoolManager getInstance() {

        if (instance == null) {
            if (PoolManager.exception != null) {
                throw new DBException(PoolManager.exception.getMessage());
            } else {
                throw new DBException("PoolManager not initialized.");
            }
        }
        return instance;
    }

    protected DBConnection getDBConnection() throws SQLException {

        DBConnection connection = null;
        if (this.pool != null) {
            connection = this.pool.getDBConnection();
        }
        return connection;
    }

    protected void releaseDBConnection(DBConnection dbConnection) throws SQLException {

        if (this.pool != null) {
            this.pool.releaseConnection(dbConnection);
        }
    }

    public synchronized void close() throws SQLException {

        this.pool.close();
        DriverManager.deregisterDriver(this.driver);
    }

    public static void destroy() {

        if (instance != null) {
            try {
                instance.close();
            } catch (SQLException se) {
                //
            }
        }
    }
}
